﻿import re
import struct
from ctypes import * 
import macro

from wbox.utils import Clipboard
from wbox.gx.core import GxStream
#from wbox.gx.program  import GxProgram
import wbox
DataFormats = Clipboard.DataFormats

DEBUG = False

from asm import Assembler
import helper

def _dump(data):
    L = []
    for d in data:
        L.append("{0:02X}".format(ord(d)))
    return " ".join(L)

def dump(data, length=16):
    LL = ["===== {0}({1:X}) =====".format(len(data), len(data))]
    L = []
    addr = 0
    for i in range(len(data)):
        L.append("{0:02X}".format(ord(data[i])))
        if i % length == length - 1:
            LL.append("{0:04X} ".format(addr) + " ".join(L))
            L = []
            addr += length
    if L:
        LL.append("{0:04X} ".format(addr) + " ".join(L))
    return "\n".join(LL)
    
def dumpint(n):
    return "{0}({0:X})".format(n)
    
empty_re = re.compile("[^\x00]")
def isEmpty(s):
    return empty_re.search(s) == None
    

class GppwDataObject(object):
    pass


class CircuitHeader(Structure):
    _fields_ = [
        ("magic",    c_byte * 8),  # 0
        ("program",  c_char * 8),  # 8
        ("fill1",    c_byte * 57), # 16
        ("start",    c_long),      # 73
        ("end",      c_long),      # 77
        ("fill2",    c_byte * 17), # 81
        ("unknown1", c_byte * 4),  # 98
        ("fill3",    c_byte * 32), # 102
        ("cpu",      c_short),     # 134
        ("unknown2", c_byte * 4),  # 136
        ("index",    c_short),     # 140
        ]                          # 142
    _pack_ = 1
        
    def __init__(self, data=None):
        if not data:
            self.magic   = (0, 0, 0x7a, 3, 3, 0, 0, 0)
            self.program = "WBOX_GEN"
            self.start   = 0
            self.end     = 0
            self.cpu     = 0xa1 # Q06UDEH
            self.cpu     = 0x90 # 144 # Q02U
            self.index   = -1
            #self.cpu     = 92 # Q06H
            #self.index   = 0
        else:
            self.unpack(data)
            
    def __len__(self):
        return sizeof(self)
            
    def unpack(self, data):
        memmove(addressof(self), data, sizeof(self))
        
    def pack(self):
        return string_at(addressof(self), sizeof(self))

    def __str__(self):
        L = []
        for name, _type in self._fields_:
            value = getattr(self, name)
            if repr(value).find("byte_Array") != -1:
                value = string_at(addressof(value), sizeof(value))
                if isEmpty(value):
                    continue
                value = dump(value)
            L.append("{0:12}: {1}".format(name, value))
        return "\n".join(L)
        
        
class GppwMidCircuit(GppwDataObject):
    _formatName_ = "CF_Gppw_Cir_Mid_Cir"
    _format_ = DataFormats.GetFormat(_formatName_)
    
    def __init__(self, data=None):
        GppwDataObject.__init__(self)
        self.header = CircuitHeader()
        self.content = ""
        if data:
            self.unpack(data)

    @property
    def data(self):
        return self.header.pack() + self.content
        
    def pack(self):
        return self.header.pack() + self.content
        
    def unpack(self, data):
        size = sizeof(CircuitHeader)
        self.header.unpack(data[:size])
        self.content = data[size:]
        
    def setIL(self, src):
        asm = Assembler()
        il = asm.parse(src)
        L = []
        count = 0
        for line in il:
            for op in line:
                L.append(op)
                count += 1
        data = "".join(L)
        length = len(data)
        x = struct.pack("2L6s", length, count, "")
        self.content = x + data
        self.header.program = "WBOX_GEN"

        
class GppwBlockList(GppwDataObject):
    _formatName_ = "CF_Gppw_BlockList"
    _format_ = DataFormats.GetFormat(_formatName_)
    
    def displayIL(self, _data):
        stream = gx.utils.GxStream(_data)
        L = []
        while True:
            data = stream.readData()
            if not data:
                break
            L.append(repr(data))
        #L.append(repr(stream.readend()))
        
        program = GxProgram(None)
        stream = gx.utils.GxStream(_data)
        program.loadBody(stream)
        L.append("\n".join(program.getLines(False)))
        
        return "\n".join(L)    
    
    def unpack(self, data):
        stream = gx.utils.GxStream(str(data))
        self.header = stream.read(142)
        
        self._unpack(stream)
        stream.readend()
        
        return self
        
    def _unpack(self, stream):
        self.blockHeader = stream.read(82)
        self.il = self.displayIL(stream.read(98300))

        temp = stream.read(0x1000)
        temp = stream.read(0x4408)
        temp = stream.read(91218-0x5408)
        temp = stream.read(148) # Block Title
        
        temp = stream.read(512*33) # Step Comment
        temp = stream.read(0x5408)
        temp = stream.read(0x1208)
        
        temp = stream.read(512*33) # Transition Comment
        temp = stream.read(0x5408)
        temp = stream.read(0x1620c)
        
        temp = stream.read(0x2ac) # 0x2ac Block statement
        
    def packdump(self, data):
        def line(data):
            length = len(data)
            i = 0
            last = None
            while i < length:
                if i + 16 < length:
                    curr = data[i:i+16]
                    if last == curr:
                        i += 16
                        continue
                    last = curr
                else: 
                    curr = data[i:]
                yield i, curr
                i += 16
        
        for i, l in line(data):
            print "{0:08X} {1}".format(i, _dump(l))
            
    def getBody(self):
        return self.il.split("=== BODY ===\n")[1]

    def __str__(self):
        return self.il
        
    
class MidCircuitViewer(GppwMidCircuit):
    def __init__(self, format, data):
        GppwMidCircuit.__init__(self)
        self.unpack(data)
        
    def compare(self, other):
        L = []
        prev = other.data
        data = self.data
        print len(prev), len(data)
        size = min(len(prev), len(data))
        for i in range(size):
            if prev[i] == data[i]:
                L.append("{0:02X}".format(ord(prev[i])))
            else:
                L.append("[{0:02X}:{1:02X}]".format(ord(prev[i]), ord(data[i])))
            if i % 16 == 15:
                L.append("\n")
        print " ".join(L)
    
    def displayIL(self, _data):
        stream = GxStream(_data)
        L = []
        while True:
            data = stream.readData()
            if not data:
                break
            L.append(repr(data))
        L.append(repr(stream.readend()))
        
        program = wbox.gx.program.GxProgram(None)
        stream = GxStream(_data)
        program.loadBody(stream)
        L.append("\n".join(program.getLines(False)))
        
        return "\n".join(L)
    
    def __str__(self):
        L = [str(self.header)]
        
        stream = GxStream(str(self.content))
        size = stream.readint()
        count = stream.readint() 
        L.append(dumpint(size))
        L.append(dumpint(count))
        L.append(dump(stream.read(6), 16))
        L.append(self.displayIL(stream.readend()))
        #L.append(dump(self.data))
        return "\n".join(L)
        
    def write(self):
        print 'write', dump(self.medium.data)

        
class GppwClipboard(object):
    def read(self):
        self.dataobj = Clipboard.GetDataObject()
        for fmtName in self.dataobj.GetFormats():
            print fmtName
            if fmtName == "CF_Gppw_Cir_Mid_Cir":
                data = self.dataobj.GetData(fmtName)
                return MidCircuitViewer(fmtName, data)
            if fmtName == "CF_Gppw_BlockList":
                data = self.dataobj.GetData(fmtName)
                return GppwBlockList().unpack(bytes(data.ToArray()))
        
    def write(self, cir):
        if type(cir) == str or type(cir) == unicode:
            ladder = cir
            cir = GppwMidCircuit()
            cir.setIL(ladder)
        il2clip(cir.pack())

        
def il2clip(data):
    #ms = data #MemoryStream(Array[Byte](list(bytes(data))))
    fmtName = GppwMidCircuit._formatName_
    Clipboard.SetDataObject(fmtName, data)

def clipfunc(f):
    data = Clipboard.GetText()
    for line in data.splitlines():
        args = [i.strip() for i in line.split("\t")]
        f(args)
        
def writeCode(src):
    cir = GppwMidCircuit()
    cir.setIL(src)
    GppwClipboard().write(cir)
    
def readCode():
    return GppwClipboard().read()
        
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        
        
def test():    
    clip = GppwClipboard()
    print clip.read()
    cir = GppwMidCircuit()
    src = """\
LD M0
OR M100
AND M1
OUT M2
"""
    print src
    cir.setIL(src)
    clip.write(cir)

if __name__ == '__main__':
    test()